package serialer

import (
	"errors"
	"io"
	"log"
	"runtime"
	"strings"
	"sync"
	"time"

	"gitee.com/haodreams/golib/logs"
)

// Serial 串口
type Serial struct {
	Connect   string
	conn      io.ReadWriteCloser
	buf       SafeBuffer
	err       error
	lock      *sync.RWMutex
	HaveRecv  bool //是否开启数据接收线程
	isRunning bool
	eventChan chan byte
}

const (
	//ConvertString 默认的转换字符串
	ConvertString = "/dev/ttyO"
)

// Closed 串口是否已经关闭
func (s *Serial) Closed() bool {
	return !s.isRunning
}

// Setup 设置
func (s *Serial) Setup() (err error) {
	s.lock = new(sync.RWMutex)
	s.eventChan = make(chan byte, 30)

	if len(s.Connect) > 3 {
		if runtime.GOOS != "windows" {
			ss := strings.ToUpper(s.Connect[:3])
			if ss == "COM" {
				s.Connect = ConvertString + s.Connect[3:]
			}
		}
	}
	_, _, _, _, _, _, err = FormatOption(s.Connect)
	s.HaveRecv = true
	return
}

func (s *Serial) read() {
	buf := make([]byte, 1024)
	logs.Info(s.Connect, "Start receive data")
	for s.isRunning {
		s.lock.RLock()
		if s.conn == nil {
			s.lock.RUnlock()
			break
		}
		n, err := s.conn.Read(buf)
		s.lock.RUnlock()
		if err != nil {
			if err.Error() != "EOF" {
				s.err = err
				log.Println(err)
				time.Sleep(time.Second)
				continue
			}
		}
		if n > 0 {
			logs.Debug("R: % 02X", buf[:n])
			if s.buf.Len() > 8192 {
				//s.buf.Reset()
				s.buf.RemoveHead4K()
			}
			s.buf.Write(buf[:n])
			s.eventChan <- 1
		}
		time.Sleep(time.Millisecond * 10)
	}
	logs.Info(s.Connect, "Stop receive data.")
}

// Open 打开
func (s *Serial) Open() (err error) {
	logs.Info("Open serial:", s.Connect)
	s.lock.Lock()
	defer s.lock.Unlock()

	s.conn, err = Open(s.Connect)
	if err != nil {
		return
	}
	if s.conn == nil {
		err = errors.New("Open faied")
		return
	}
	s.buf.Reset()
	s.err = nil
	s.isRunning = true
	if s.HaveRecv {
		go s.read()
	}
	return
}

// Close 关闭
func (s *Serial) Close() (err error) {
	if s.conn != nil {
		logs.Info("Close serial:", s.Connect)
		err = s.conn.Close()
		s.lock.Lock()
		s.conn = nil
		s.lock.Unlock()
	}
	s.isRunning = false
	//log.Println("============close")

	return
}

// Write 写数据
func (s *Serial) Write(p []byte) (n int, err error) {
	if s.conn == nil {
		err = errors.New("Not connected")
		return
	}

	n, err = s.conn.Write(p)
	if err == nil && n > 0 {
		logs.Debug("S: % 02X", p[:n])
	}
	return
}

// Read 读数据
func (s *Serial) Read(p []byte) (n int, err error) {

	//清空事件
	numEvent := len(s.eventChan)
	for ; numEvent > 0; numEvent-- {
		<-s.eventChan
	}

	if s.conn == nil {
		err = errors.New("Not connected")
		return
	}
	if s.err != nil {
		return 0, s.err
	}

	if s.buf.Len() > 0 {
		n, err = s.buf.Read(p)
		if err != nil {
			return
		}
		if err == nil && n > 0 {
			//logs.Info("R: % 02X", p[:n])
		}
		return
	}
	select {
	case <-time.After(time.Second):
		//	err = errors.New("timeout")
		return
	case <-s.eventChan:
		n, err = s.buf.Read(p)
		if err != nil {
			if err.Error() == "EOF" {
				err = nil
			}
			//log.Println(err)
			return
		}
	}

	if err == nil && n > 0 {
		//logs.Info("R: % 02X", p[:n])
	}
	return
}

// Len 获取buf 数据的长度
func (s *Serial) Len() int {
	return s.buf.Len()
}

// Reset 清空数据
func (s *Serial) Reset() {
	//logs.Debug("reset bufer")
	s.buf.Reset()
}
